#include "../include/engine/graphics.h"
#include "../include/modules/square.h"
#include "../include/modules/monster.h"
#include "../include/modules/tower.h"
#include "../include/geometry/shapeGL.h"
#include <stdio.h>
#include <stdlib.h>

void drawAll(Itd itd, Map *map, List *listM, List *listT, Player *player){
	glClear(GL_COLOR_BUFFER_BIT);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    drawMap(map->texture);

    if(map->debug == 1){                                    // Gère tous les affichages en mode debug.
        drawRoad(map->nodesGL, itd);                        //On dessine le chemin
        drawNode(map->nodesGL, itd);                        //On dessine les noeuds
        foreachList(node, *listT){                          //On dessine toutes les ranges
            drawRange(node->data);
        }
        if(map->squareDrew.initSquare != 0){                // Au premier lancement le square n'est pas init donc ne pas le dessiner.
            drawSquare(map->squareDrew);
        }
        for(int i = 0; i<map->nbSquare; i++){               // On parcours tous les carrés pour dessiner une grille.
            drawSquareGrid(map->squareTab[i]);
        }
    }    
    if(player->constructMode == 1 && map->debug == 0){      // Gère tous les affichages en mode constructible.
        foreachList(node, *listT){
            drawRange(node->data);
        }
        if(map->squareDrew.initSquare != 0){                // Au premier lancement le square n'est pas init donc ne pas le dessiner.
            drawSquare(map->squareDrew);
        }
        for(int i = 0; i<map->nbSquare; i++){               // On parcours tous les carrés pour dessiner une grille.
            drawSquareGrid(map->squareTab[i]);
        }
    }

    foreachList(node, *listT){
        Tower *t = (Tower *)node->data;
        if(t->select == 1){                                 //Si une tour est select alors on dessine son range
            drawRange(node->data);
        }
        drawTower(node->data);
    }
    foreachList(node, *listM){                              // Affichage des Monstres.
        Monster *m = (Monster *)node->data;
        if(m->select == 1){
            drawMonsterSelect(m);
        }
        drawMonster(node->data);
        drawLifeMonster(node->data);
    }
}

GLuint createTexture(GLuint texture, SDL_Surface *image){
    if(image == NULL){
        fprintf(stderr, "createTexture::Le pointeur image de SDL_Surface n'existe pas\n");
        return texture;
    }
    /*Génération texture*/
    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexImage2D(
          GL_TEXTURE_2D, 
          0, 
          GL_RGBA, 
          image->w, 
          image->h, 
          0, 
          getSurfaceFormat(image),
          GL_UNSIGNED_BYTE, 
          image->pixels
        );
    glBindTexture(GL_TEXTURE_2D, 0);

    return texture;
}

void definePixel(SDL_Surface *imgMap, int x, int y, Uint32 pixel){
    int nbOctetsParPixel = imgMap->format->BytesPerPixel;
    Uint8 *p = (Uint8 *)imgMap->pixels + y * imgMap->pitch + x * nbOctetsParPixel;
 
    /*Gestion différente suivant le nombre d'octets par pixel de l'image*/
    switch(nbOctetsParPixel){
        case 1:
            *p = pixel;
            break;
        case 2:
            *(Uint16 *)p = pixel;
            break;
        case 3:
            /*Suivant l'architecture de la machine*/
            if(SDL_BYTEORDER == SDL_BIG_ENDIAN){
                p[0] = (pixel >> 16) & 0xff;
                p[1] = (pixel >> 8) & 0xff;
                p[2] = pixel & 0xff;
            }
            else{
                p[0] = pixel & 0xff;
                p[1] = (pixel >> 8) & 0xff;
                p[2] = (pixel >> 16) & 0xff;
            }
            break;
        case 4:
            *(Uint32 *)p = pixel;
            break;
    }
}

Uint32 getPixel(SDL_Surface *imgMap, int x, int y){
    int nbOctetsParPixel = imgMap->format->BytesPerPixel;
    Uint8 *p = (Uint8 *)imgMap->pixels + y * imgMap->pitch + x * nbOctetsParPixel;
 
    /*Gestion différente suivant le nombre d'octets par pixel de l'image*/
    switch(nbOctetsParPixel){
        case 1:
            return *p;
            break;
        case 2:
            return *(Uint16 *)p;
            break;
        case 3:
            /*Suivant l'architecture de la machine*/
            if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
                return p[0] << 16 | p[1] << 8 | p[2];
            else
                return p[0] | p[1] << 8 | p[2] << 16;
            break;
        case 4:
            return *(Uint32 *)p;
            break;
        default:
            return 0;
            break;
    }
}

GLenum getSurfaceFormat(SDL_Surface* img){
    GLenum format;

    switch(img->format->BytesPerPixel){
        case 1:
            format = GL_RED;
            break;
        case 3:
            /* Ne gere pas les machines big-endian (a confirmer...) */
            format = GL_RGB;
            break;
        case 4:
            /* Ne gere pas les machines big-endian (a confirmer...) */
            format = GL_RGBA;
            break;
        default:
            /* On ne traite pas les autres cas */
            fprintf(stderr, "Format des pixels de l'image non pris en charge\n");
            return EXIT_FAILURE;
    }
    return format;
}